package org.jeecg.modules.boc.service;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.boc.config.InfoConfig;
import org.jeecg.modules.boc.entity.AccessTokenVO;
import org.jeecg.modules.boc.entity.BO.MessageBO;
import org.jeecg.modules.boc.entity.GetUserInfoVO;
import org.jeecg.modules.boc.entity.MessageVO;
import org.jeecg.modules.boc.enums.ResultEnum;
import org.jeecg.modules.boc.exception.ControllerException;
import org.jeecg.modules.boc.utils.http.HttpsClient;
import org.jeecg.modules.boc.utils.retrofit2.HTTP;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.jeecg.modules.system.mapper.SysUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;

/**
 * 第三方App对接：中行行信实现类
 *
 * @author: jeecg-boot
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
public class ThirdAppBocWechatServiceImpl implements BankWeChatService {

    @Autowired
    private SysDictMapper sysDictMapper;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private RedisUtil redisUtil;
    /**
     * errcode
     */
    private static final String ERR_CODE = "errcode";

    //行信企业号
    private String CORP_ID = "wl51276822a8";
    //行信企业密码
    private String CORP_SECRET = "pB06fBJ7FHOR1sFY-iVvYH4lqJwIqwZtrGomqs2YbYM";

    /**
     * 访问行信获取access_token
     *
     * @param corpid 企业id
     * @param secret 应用的密钥
     * @return
     */
    @Override
    public JSONObject registApp(String corpid, String secret) {
        log.info("registApp---corpid：{},secret:{}", corpid, secret);
        String baseUrl = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.BASE_URL);
        //返回token JSON
        JSONObject tokenJson = new JSONObject();
        int expires_in = 7200;
//        String requestType = bankWeChatMapper.queryBasicsDataName(InfoConfig.BANK_WE_CHAT,InfoConfig.REQUEST_TYPE, DataTypeEnum.BASICS_DATA_ON.key().toString());
        //测试开关 1、打开；2、关闭
        String testFlag = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.TEST_FLAG);
        if ("2".equals(testFlag)) {
            //请求行信
            HTTP http = HTTP.getInstance(baseUrl);
            HttpService httpService = http.getRequest(HttpService.class);
            AccessTokenVO accessTokenBO = http.synVisit(httpService.regist(corpid, secret));
            log.info("registApp---accessTokenBO:{}", accessTokenBO);
            if ("0".equals(accessTokenBO.getErrcode())) {
                ResultEnum.TOKEN_ERROR.setMsg(accessTokenBO.getErrmsg());
                throw new ControllerException(ResultEnum.TOKEN_ERROR);
            }
            tokenJson.put("errcode", accessTokenBO.getErrcode());
            tokenJson.put("errmsg", accessTokenBO.getErrmsg());
            tokenJson.put("access_token", accessTokenBO.getAccess_token());
            expires_in = Integer.valueOf(accessTokenBO.getExpires_in());
            tokenJson.put("expires_in", expires_in);
        } else {

            //TODO 测试环境，可以随便赋值
            HttpsClient httpsClient = new HttpsClient();
            //TODO 本地测试完需要修改
//            String url = baseUrl + "cgi-bin/gettoken?corpid=" + corpid + "&corpsecret=" + secret;
//            String url=baseUrl + "operateCulture/gettoken?corpid="+corpid+"&corpsecret="+secret;//本地测试使用
            //TODO 本地测试完需要修改
//            JSONObject resultJSON = httpsClient.httpsGet(url);
//            JSONObject resultJsonUpdate = httpsClient.httpsGet(url);//本地测试使用
//            JSONObject resultJSON = resultJsonUpdate.getJSONObject("result");//本地测试使用
//            log.info("registApp---errcode:{},access_token:{}", resultJSON.getInteger("errcode"), resultJSON.getString("access_token"));
            /*if (resultJSON.getInteger("errcode") != 0) {
                ResultEnum.TOKEN_ERROR.setMsg(resultJSON.getString("errmsg"));
                throw new ControllerException(ResultEnum.TOKEN_ERROR);
            }
            tokenJson.put("errcode", resultJSON.getInteger("errcode"));
            tokenJson.put("errmsg", resultJSON.getString("errmsg"));
            tokenJson.put("access_token", resultJSON.getString("access_token"));
            expires_in = resultJSON.getInteger("expires_in");
            tokenJson.put("expires_in", expires_in);*/

            tokenJson.put("errcode", "0");
            tokenJson.put("errmsg", "成功");
            tokenJson.put("access_token", "abcdefghijk");
            tokenJson.put("expires_in", expires_in);
        }

        //TODO  暂时不考虑一期
//        bankWeChatMapper.updateBasicsDataName(InfoConfig.BANK_WE_CHAT,InfoConfig.TOKEN,tokenJson.getString("access_token"));
        redisUtil.set(InfoConfig.EWR_HO + secret, tokenJson.getString("access_token"), expires_in);

        return tokenJson;
    }

    /**
     * 平台使用接口获取access_token,第二个appsecret用平台的corpsecret代替
     * (参考 bocwechat-boot )
     *
     * @return
     */
    @Override
    public String getAcessToken() throws Exception {
        //corpSecret 需要发送到平台的secret
//            String corpSecret = bankWeChatMapper.queryBasicsDataName(InfoConfig.BANK_WE_CHAT,InfoConfig.CORP_SECRET, DataTypeEnum.BASICS_DATA_ON.key().toString());
        String corpSecret = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.CORP_SECRET);
//            String corpid = bankWeChatMapper.queryBasicsDataName(InfoConfig.BANK_WE_CHAT,InfoConfig.CORP_ID, DataTypeEnum.BASICS_DATA_ON.key().toString());
        String corpid = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.CORP_ID);
        if (StringUtils.isBlank(corpid))
            corpid = CORP_ID;
        if (StringUtils.isBlank(corpSecret))
            corpSecret = CORP_SECRET;

        //TODO 2023-12-11 17:27:23 暂时不考虑一期的情况
        String token = String.valueOf(redisUtil.get(InfoConfig.EWR_HO + corpSecret));
        log.info("getAcessToken----根据corpSecret【{}】从redis中获取token【{}】", corpSecret, token);
        if (StringUtils.isBlank(token)) {
            JSONObject tokenJson = registApp(corpid, corpSecret);
            token = tokenJson.getString("access_token");
        }
        log.info("getAcessToken----token:{}", token);
        return token;
    }

    /**
     * 回调地址携带 code --> bankCode 是为了避免与 "result-code" 重复
     *
     * @param bankCode
     * @return
     * @throws Exception
     */
    @Override
    public JSONObject getCode(String bankCode, String stateValue) throws Exception {
        log.info("回调getCode-code【{}】，state【{}】 ", bankCode, stateValue);
        if (StringUtils.isBlank(bankCode))
            throw new ControllerException(ResultEnum.CODE_ERROR);

        //TODO 2023年12月12日11:48:15 修改成存到redis
        log.info("将stateValue作为key，bankCode作为value，并设置过期时间存到redis中");
        redisUtil.set(InfoConfig.EWR_HO + stateValue, bankCode, InfoConfig.CODE_OUT_TIME);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("bankCode", bankCode);
        jsonObject.put("stateValue", stateValue);
        log.info("getCode----jsonObject:{}", jsonObject);
        return jsonObject;
    }

    @Override
    public GetUserInfoVO getUserInfo(String bankCode) throws Exception {
        //TODO 2023-12-11 code改为前端获取然后传到后台
//        log.info("getUserInfo-根据stateValue【{}】从redis中查询bankCode是否存在", stateValue);
//        String bankCode = String.valueOf(redisUtil.get(InfoConfig.EWR_HO + stateValue));
        String token = getAcessToken();
        log.info("getuserinfo---token:{},bankCode:{}", token, bankCode);
        //总行地址 : https://imp.bank-of-china.com/
        String baseUrl = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.BASE_URL);
        log.info("getUserInfo----baseUrl:{}", baseUrl);
        GetUserInfoVO getUserInfoVo = new GetUserInfoVO();
        //测试开关 1、打开；2、关闭
        String testFlag = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.TEST_FLAG);
        if ("2".equals(testFlag)) {
            HTTP http = HTTP.getInstance(baseUrl);
            HttpService httpService = http.getRequest(HttpService.class);
            getUserInfoVo = http.synVisit(httpService.getUserInfo(token, bankCode));
            log.info("getUserInfoVo:{}", getUserInfoVo);
            if (!"0".equals(getUserInfoVo.getErrcode())) {

                ResultEnum.USER_INFO_ERROR.setMsg(getUserInfoVo.getErrmsg());
                throw new ControllerException(ResultEnum.USER_INFO_ERROR);
            }

        } else {
            HttpsClient httpsClient = new HttpsClient();
            //TODO 本地测试完需要修改
            String url = baseUrl + "cgi-bin/user/getuserinfo?access_token=" + token + "&code=" + bankCode;
//            String url= baseUrl + "operateCulture/getuserinfo?access_token="+token+"&code="+bankCode;//本地测试使用
            //TODO 本地测试完需要修改
            JSONObject resultJSON = httpsClient.httpsGet(url);
//            JSONObject resultJsonUpdate = httpsClient.httpsGet(url);//本地测试使用
//            JSONObject resultJSON = resultJsonUpdate.getJSONObject("result");//本地测试使用
//            log.info("返回结果-resultJSON-result："+resultJSON.getJSONObject("result"));
            if (resultJSON.getInteger("errcode") != 0) {
                ResultEnum.USER_INFO_ERROR.setMsg(resultJSON.getString("errmsg"));
                throw new ControllerException(ResultEnum.USER_INFO_ERROR);
            }

            getUserInfoVo = JSONObject.parseObject(resultJSON.toJSONString(), GetUserInfoVO.class);
        }

        log.info("getUserInfo----getUserInfoVo:{}", getUserInfoVo.toString());
        return getUserInfoVo;
    }

    /**
     * 根据 state  查询 code 是否拿到了
     *
     * @param stateValue
     * @return
     * @throws Exception
     */
    public JSONObject queryCodeByState(String stateValue) throws Exception {
        log.info("queryCodeByState-根据stateValue【{}】从redis中查询bankCode是否存在", stateValue);
        String bankCode = String.valueOf(redisUtil.get(InfoConfig.EWR_HO + stateValue));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("bankCode", bankCode);
        log.info("queryCodeByState----jsonObject:{}", jsonObject);
        return jsonObject;
    }

    /**
     * 根据 userIds token content 发送消息给 userIds
     *
     * @return
     */
    @Override
    public JSONObject sendMsg(List<String> userIds, String content) throws Exception {
        //TODO 2023-12-11
        String token = getAcessToken();
        log.info("sendMsg---token:{}", token);

        //总行地址 :https://imp.bank-of-china.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
        String baseUrl = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.BASE_URL);
        String toparty = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.TO_PARTY);
        String totag = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.TO_TAG);
        String msgtype = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.MSG_TYPE);
        String agentid = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.AGENT_ID);

        // userId成员id之间的连接符
        StringBuilder touserSB = new StringBuilder();
        for (int i = 0; i < userIds.size(); i++) {
            touserSB.append(userIds.get(i)).append("|");
        }
        String touser = touserSB.toString().substring(0, touserSB.length() - 1);

        MessageBO messageBO = new MessageBO();
        messageBO.setTouser(touser);//成员ID列表（消息接收者，多个接收者用‘|’分隔，最多支持1000个）。特殊情况：指定为@all，则向该企业应用的全部成员发送
        messageBO.setToparty(toparty);//	部门ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
        messageBO.setTotag(totag);//	标签ID列表，多个接收者用‘|’分隔，最多支持100个。当touser为@all时忽略本参数
        messageBO.setMsgtype(msgtype);//消息类型，此时固定为：text; text|image|voice|video|file|textcard|news|miniprogram_notice|
        messageBO.setAgentid(Integer.parseInt(agentid));//企业应用的id，整型。可在应用的设置页面查看
        messageBO.setContent(content);//消息内容，最长不超过2048个字节

        log.info("发送消息POST请求参数：token:{},messageBO:{}", token, messageBO);

        JSONObject jsonObject = new JSONObject();

        //主动发送消息的请求方式：1：一期方式请求行信；2：二期方式请求 ；
//        String requestType = bankWeChatMapper.queryBasicsDataName(InfoConfig.BANK_WE_CHAT, InfoConfig.REQUEST_TYPE, DataTypeEnum.BASICS_DATA_ON.key().toString());
        //测试开关 1、打开；2、关闭
        String testFlag = sysDictMapper.queryDictTextByKey(InfoConfig.BANK_WE_CHAT, InfoConfig.TEST_FLAG);
        if ("2".equals(testFlag)) {
            HTTP http = HTTP.getInstance(baseUrl);
            HttpService httpService = http.getRequest(HttpService.class);
            MessageVO messageVO = http.synVisit(httpService.send(token, messageBO));
            log.info("messageVO:{}", messageVO);
            if ("0".equals(messageVO.getErrcode())) {
                log.info("发送消息成功");
                jsonObject.put("errcode", messageVO.getErrcode());
                jsonObject.put("errmsg", messageVO.getErrmsg());
            } else {
                log.info("发送消息失败");
                ResultEnum.SEND_MESSAGE_ERROR.setMsg(messageVO.getErrmsg());
                throw new ControllerException(ResultEnum.SEND_MESSAGE_ERROR);
            }
        } else {
            //2：二期方式请求
            HttpsClient httpsClient = new HttpsClient();
            //TODO 本地测试完需要修改
            String url = baseUrl + "cgi-bin/message/send";
//            String url= baseUrl + "operateCulture/send";//本地测试使用
            JSONObject paramJson = new JSONObject();
            paramJson.put("access_token", token);
            paramJson.put("touser", touser);
            paramJson.put("toparty", toparty);
            paramJson.put("totag", totag);
            paramJson.put("msgtype", msgtype);
            paramJson.put("agentid", agentid);
            paramJson.put("text", new JSONObject().put("content", content));
            String param = JSONObject.toJSONString(paramJson);
            log.info("param:{},paramJson:{}", param, paramJson);
            //TODO 本地测试完需要修改
            JSONObject resultJSON = httpsClient.httpsPost(url, param);
//            JSONObject resultJsonUpdate = httpsClient.httpsPost(url,param);//本地测试使用
//            JSONObject resultJSON = resultJsonUpdate.getJSONObject("result");//本地测试使用
            if (resultJSON.getInteger("errcode") != 0) {
                ResultEnum.SEND_MESSAGE_ERROR.setMsg(resultJSON.getString("errmsg"));
                throw new ControllerException(ResultEnum.SEND_MESSAGE_ERROR);
            }
            jsonObject.put("errcode", resultJSON.getInteger("errcode"));
            jsonObject.put("errmsg", resultJSON.getString("errmsg"));

        }

        return jsonObject;
    }

    //第三方统一发送消息
    public boolean sendMessage(MessageDTO message) throws Exception {

        List<String> userIds = Arrays.asList(message.getToUser().split(","));
        String content = message.getContent();
        JSONObject jsonObject = sendMsg(userIds, content);
        if ("0".equals(jsonObject.get("errcode"))) {
            return true;
        } else {
            return false;
        }
    }

}
